﻿using Innoapps.FileTransfer.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace Innoapps.FileTransfer.Providers.State
{
    public class InProcess : Base
    {

        #region Constructors

        public InProcess()
        {
            // If the routing folder exists then begin process
            if(Directory.Exists(routingFolder))
            {
                // Get routing folder info
                DirectoryInfo routingFolderInfo = new DirectoryInfo(routingFolder);
                // Loop sub folders within routing folder
                foreach(DirectoryInfo stageFolder in routingFolderInfo.GetDirectories())
                {
                    // If the stage folder does not contain completed transfers then proceed to load xml files fro this directory
                    if(stageFolder.Name != "Innoapps.FileTransfer.Providers.State.Complete" && stageFolder.Name != "Innoapps.FileTransfer.Providers.State.Failure")
                    {
                        // Loop the xml files in the stage folder
                        foreach (FileInfo xmlDoc in stageFolder.GetFiles("*.xml"))
                        {

                            // load the transfer into the in memory transfers list
                            Transfer transfer = (Transfer)xmlHelperData.Read(xmlDoc.FullName, "http://innoapps.co.uk/FileTransfer/Transfer");
                            transfer.NextAction = stageFolder.Name;
                            transfer.NextAction_Scheduled = DateTime.Now;
                            transfer.InProcess = false;

                            transfers.Add(transfer);

                        }
                    }
                }
            }
        }

        #endregion



        #region Variables
        private string routingFolder;
        List<Models.Transfer> transfers = new List<Models.Transfer>();
        #endregion

        #region Properties


        [XmlAttribute("RoutingFolder")]
        public string RoutingFolder
        {
            get { return routingFolder; }
            set
            {
                Directory.CreateDirectory(value);
                routingFolder = value;
            }
        }
        #endregion

        #region Methods
        

        public override Transfer GetTransfer()
        {
            // Find a transfer where the next action is ready to be ran and the transfer is not in process
            Transfer next = (from r in transfers where r.NextAction_Scheduled <= DateTime.Now && r.InProcess == false orderby r.NextAction_Scheduled ascending select r).FirstOrDefault();

            // If no transfer is found then return null
            if(next == null)
            {
                return null;
            } else
            {
                // Set the found transfer state to in process
                next.InProcess = true;
                // Return the found transfer
                return next;
            }

        }

        public override void ProcessActionResult(Models.Transfer transfer)
        {

            

            // If the transfer is new then add it to memory
            if (transfer.IsNew)
                transfers.Add(transfer);

            // If the transfer is not in memory then exit the method
            if (!transfers.Contains(transfer))
                return;

            // Get the last transfer event
            ActionResult lastActionResult = transfer.ActionResults.Last();

            // if the event states that the action was complete then move to the next stage
            if (lastActionResult.Result == "Complete")
            {
                // Get the next state for the transfer
                StateListItem newState = GetNextState(lastActionResult.Action);

                // Update the transfer activity and action
                transfer.NextAction = newState.Action;

                // Ensure that a folder exists for the new routing slip
                Directory.CreateDirectory(Path.Combine(routingFolder, newState.Action));

                // Create a new routing slip in the routing folder relating to the new state
                xmlHelperData.Save(Path.Combine(routingFolder, newState.Action, transfer.Id + ".xml"), transfer, "http://innoapps.co.uk/FileTransfer/Transfer");


                // Delete the old routing slip
                File.Delete(Path.Combine(routingFolder, lastActionResult.Action, transfer.Id + ".xml"));

                

                // Update the current state
                transfer.InProcess = false;


            }
            // Process errored action
            else if (lastActionResult.Result == "Error")
            {
                // Save the new routing slip to disk
                xmlHelperData.Save(Path.Combine(routingFolder, transfer.NextAction, transfer.Id + ".xml"), transfer, "http://innoapps.co.uk/FileTransfer/Transfer");
                // Set transfer to not in process
                transfer.InProcess = false;
            } else { // Process transfer Failure

                // Ensure that a folder exists for the new routing slip
                Directory.CreateDirectory(Path.Combine(routingFolder, "Innoapps.FileTransfer.Providers.State.Failure"));

                // Create a new routing slip in the routing folder relating to the new state
                xmlHelperData.Save(Path.Combine(routingFolder, "Innoapps.FileTransfer.Providers.State.Failure", transfer.Id + ".xml"), transfer, "http://innoapps.co.uk/FileTransfer/Transfer");

                // Delete the old routing slip
                File.Delete(Path.Combine(routingFolder, lastActionResult.Action, transfer.Id + ".xml"));

                // Remove the transfer from memory
                transfers.Remove(transfer);

            }

        }


        public override void Complete(Transfer transfer)
        {
            // Remove the transfer from memory
            transfers.Remove(transfer);
        }

        #endregion

    }
}
